package com.zhang.infrastructure.util.excel;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.util.MapUtils;
import com.alibaba.excel.util.StringUtils;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.style.row.SimpleRowHeightStyleStrategy;
import com.alibaba.fastjson.JSON;
import com.zhang.infrastructure.model.KingHoodException;
import com.zhang.infrastructure.model.constant.ExceptionConstant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * EasyExcel导出工具类
 *
 * @author jp
 * @date 2023/12/25
 */
public class EasyExcelUtil {
    static Logger log = LoggerFactory.getLogger(EasyExcelUtil.class);

    /**
     * 读excel
     *
     * @param file  文件
     * @param clazz class
     * @return list
     * @auther zhangFanJun
     * @date 2023/12/26
     */
    public static <T> List<T> readExcel(MultipartFile file, Class<T> clazz) throws IOException {
        return EasyExcel.read(file.getInputStream())
                .head(clazz)
                .sheet()
                .doReadSync();
    }

    /**
     * 导出excel
     *
     * @param response 响应
     * @param clazz    class
     * @param name     名字
     * @return list
     * @auther zhangFanJun
     * @date 2023/12/26
     */
    public static <T> void writeExcel(HttpServletResponse response, List<T> dataList, Class<T> clazz, String name) throws IOException {
        try {
            response.setHeader("Access-Control-Expose-Headers","Content-disposition");
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            String fileName = URLEncoder.encode(name, "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
//            response.setContentType("application/octet-stream;charset=utf-8");
//            response.setHeader("Content-Disposition", "attachment; filename=" + new String(name.getBytes(), "iso-8859-1") + ".xlsx");
//            response.setHeader("Content-Disposition", "attachment; filename=" + fileName + ".xlsx");
            EasyExcel.write(response.getOutputStream(), clazz).autoCloseStream(Boolean.FALSE).sheet(name)
                    .doWrite(dataList);
        } catch (Exception e) {
            // 重置response
            response.reset();
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            Map<String, String> map = MapUtils.newHashMap();
            map.put("status", "failure");
            map.put("message", "下载文件失败" + e.getMessage());
            response.getWriter().println(JSON.toJSONString(map));
        }
    }

    /**
     * 可指定部分导出字段方法
     *
     * @param response
     * @param fileName  文件名称
     * @param sheetName sheet名称
     * @param dataList  需要导出的数据
     * @param clazz     类
     * @param showParam 只展示的字段,多个通过逗号分割拼接(如：String showParam = “institutionName,creditCode,institutionStatus”)
     * @param <T>
     * @throws IOException
     */
    public static <T> String export(HttpServletResponse response, String fileName, String sheetName, List<T> dataList, Class<T> clazz, String showParam, String filePath) throws IOException {
        String saveName = setExportResponseHeader(fileName, response);
        Set<Integer> selectedIndexes = new HashSet<>();
        if (StringUtils.isNotBlank(showParam)) {
            String[] strList = showParam.split(",");
            // 反射获取字段属性
            Field[] declaredFields = clazz.getDeclaredFields();
            for (int i = 0; i < declaredFields.length; i++) {
                for (String s : strList) {
                    // 与需要展示的字段匹配
                    if (declaredFields[i].getName().equals(s)) {
                        // 获取展示字段的下标
                        selectedIndexes.add(i);
                        break;
                    }
                }
            }
        }
        if (StringUtils.isNotBlank(filePath)) {
            String path = filePath+"/"+ URLDecoder.decode(saveName, "UTF-8")+ ".xlsx";
            File saveFile = new File(path);
            log.info("保存文件地址：{}",saveFile.getAbsolutePath());
            saveFile.createNewFile();
            if (!selectedIndexes.isEmpty()) {
                EasyExcel.write(saveFile, clazz).includeColumnIndexes(selectedIndexes).sheet(sheetName).doWrite(dataList);
                EasyExcel.write(response.getOutputStream(), clazz).includeColumnIndexes(selectedIndexes).sheet(sheetName).doWrite(dataList);
            } else {
                EasyExcel.write(saveFile, clazz).sheet(sheetName).doWrite(dataList);
                EasyExcel.write(response.getOutputStream(), clazz).sheet(sheetName).doWrite(dataList);
            }
            return path;
        } else {
            if (!selectedIndexes.isEmpty()) {
                EasyExcel.write(response.getOutputStream(), clazz).includeColumnIndexes(selectedIndexes).sheet(sheetName).doWrite(dataList);
            } else {
                EasyExcel.write(response.getOutputStream(), clazz).sheet(sheetName).doWrite(dataList);
            }
        }
        return null;
    }

    /**
     * excel 动态导出
     *
     * @param response
     * @param excelExport excel数据
     * @author jp
     * @date 2023/12/19
     */
    public static String exportDynamic(HttpServletResponse response, ExcelExportWriter excelExport, short height, String filePath) throws Exception {
        if (Objects.isNull(excelExport)) {
            throw new KingHoodException(ExceptionConstant.CODE_BAD_SERVER ,"导出数据配置不能为空");
        }
        String saveName = setExportResponseHeader(excelExport.getFileName(), response);

        WriteSheet sheet = EasyExcel.writerSheet(1).build();
        sheet.setSheetName(excelExport.getSheetName());
        sheet.setHead(excelExport.getHeads());
        if (StringUtils.isNotBlank(filePath)) {
            String path = filePath+"/"+ URLDecoder.decode(saveName, "UTF-8")+ ".xlsx";
            File saveFile = new File(path);
            log.info("保存文件地址：{}",saveFile.getAbsolutePath());
            saveFile.createNewFile();

            try (ExcelWriter writer = EasyExcel.write(saveFile)
                    .registerWriteHandler(new SimpleRowHeightStyleStrategy((short) 20, height))
                    .registerWriteHandler(new MyColumnWidthStyleStrategy())
                    .build()) {
                writer.write(excelExport.getDatas(), sheet);
            }catch (Exception e){
                log.error("export file error!", e);
                throw new KingHoodException(ExceptionConstant.CODE_BAD_SERVER, e.getMessage());
            }
            try (ExcelWriter writer2 = EasyExcel.write(response.getOutputStream())
                    .registerWriteHandler(new SimpleRowHeightStyleStrategy((short) 20, height))
                    .registerWriteHandler(new MyColumnWidthStyleStrategy())
                    .build()) {
                writer2.write(excelExport.getDatas(), sheet);
            }catch (Exception e){
                log.error("export file error!", e);
                throw new KingHoodException(ExceptionConstant.CODE_BAD_SERVER, e.getMessage());
            }
            return path;
        } else {
            try (ExcelWriter writer = EasyExcel.write(response.getOutputStream())
                    .registerWriteHandler(new SimpleRowHeightStyleStrategy((short) 20, height))
                    .registerWriteHandler(new MyColumnWidthStyleStrategy())
                    .build()) {
                writer.write(excelExport.getDatas(), sheet);
            }catch (Exception e){
                log.error("export file error!", e);
                throw new KingHoodException(ExceptionConstant.CODE_BAD_SERVER, e.getMessage());
            }
            return null;
        }
    }

    /**
     * 设置导出响应标头
     *
     * @param fileName 文件名
     * @param response 回答
     * @author jp
     * @date 2023/12/19
     */
    private static String setExportResponseHeader(String fileName, HttpServletResponse response) throws UnsupportedEncodingException {
        // 设置响应头和保存文件名
        response.setHeader("Access-Control-Expose-Headers","Content-disposition");
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("UTF-8");
        DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyMMddHHmmss");
        String dataStr = dtf2.format(LocalDateTime.now());
        fileName = URLEncoder.encode(fileName+dataStr, "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        return fileName;
    }
}
